#include <iostream>
#include <alsa/asoundlib.h>
#include "minimp3/minimp3_ex.h"
#include "RingBuffer.h"
#include "EventCallback.h"

class Player {
public:
    Player(RingBuffer &buffer, int sample_rate = 44100)
        : buffer_(buffer)
        , mp3_{}
        , pcm_buffer_(PCM_BUFFER_SIZE)
        , stop_(false)
        , paused_(false)
        , sample_rate_(sample_rate)
        , sample_ch_(2)
    {
        mp3dec_init(&mp3_);
    }

    ~Player()
    {
        Stop();
        if (pcm_handle_)
            snd_pcm_close(pcm_handle_);
    }

    bool Initialize()
    {
        int err = snd_pcm_open(&pcm_handle_, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0) {
            last_error_ = "ALSA open error: " + std::string(snd_strerror(err));
            return false;
        }

        err = snd_pcm_set_params(pcm_handle_, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED,
            sample_ch_, // stereo
            sample_rate_,
            1,      // allow resampling
            50000); // latency (us)
        if (err < 0) {
            last_error_ = "ALSA set params error: " + std::string(snd_strerror(err));
            return false;
        }
        return true;
    }

    bool ALSAReconfig(int rate, int chn)
    {
        if (rate == sample_rate_ && chn == sample_ch_) {
            return true;
        }

        std::cout << "reconfig target rate: " << rate << " channels:" << chn << std::endl;

        if (pcm_handle_) {
            snd_pcm_close(pcm_handle_);
            pcm_handle_ = nullptr;
        }

        int err = snd_pcm_open(&pcm_handle_, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0)
            return false;

        sample_rate_ = rate;
        sample_ch_ = chn;

        snd_pcm_set_params(pcm_handle_, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED,
            sample_ch_, // stereo
            sample_rate_,
            1,      // allow resampling
            50000); // latency (us)

        return true;
    }

    void Start()
    {
        if (playing_)
            return;
        stop_ = false;
        paused_ = false;
        playing_ = true;
        worker_ = std::thread(&Player::PlayThread, this);
    }

    void Pause()
    {
        if (!playing_ || paused_)
            return;
        paused_ = true;
    }

    void Resume()
    {
        if (!playing_ || !paused_)
            return;
        paused_ = false;
    }

    void Stop()
    {
        if (!playing_)
            return;
        stop_ = true;
        if (worker_.joinable())
            worker_.join();
        playing_ = false;
        paused_ = false;
    }

    void SetEventCallback(EventCallback *callback)
    {
        callback_ = callback;
    }

private:
    static constexpr size_t PCM_BUFFER_SIZE = 1152 * 4; // MP3 frame size

    void PlayThread()
    {
        std::vector<uint8_t> mp3_data(4096);
        size_t pending = 0;

        while (!stop_) {
            if (paused_) {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }

            // 从环形缓冲区读取MP3数据
            size_t read = buffer_.Read(mp3_data.data() + pending, mp3_data.size() - pending);
            if (read == 0) {
                // 检查是否结束
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }

            size_t total_size = pending + read;
            size_t offset = 0;

            while (offset < total_size) {
                mp3dec_frame_info_t info;
                int samples = mp3dec_decode_frame(&mp3_, mp3_data.data() + offset, total_size - offset,
                    reinterpret_cast<short *>(pcm_buffer_.data()), &info);

                if (samples > 0) {
                    ALSAReconfig(info.hz, info.channels);

                    // 播放PCM数据
                    snd_pcm_sframes_t frames = snd_pcm_writei(pcm_handle_, pcm_buffer_.data(), samples);

                    if (frames < 0) {
                        frames = snd_pcm_recover(pcm_handle_, frames, 0);
                        if (frames < 0) {
                            if (callback_) {
                                callback_->OnPlayError("ALSA write error: " + std::string(snd_strerror(frames)));
                            }
                        }
                    }
                }

                if (info.frame_bytes == 0)
                    break;
                offset += info.frame_bytes;
            }

            // 保存未处理的数据
            pending = total_size - offset;
            if (pending > 0) {
                std::copy(mp3_data.begin() + offset, mp3_data.begin() + total_size, mp3_data.begin());
            }
        }
    }

    RingBuffer &buffer_;
    mp3dec_t mp3_;
    snd_pcm_t *pcm_handle_ = nullptr;
    std::vector<uint8_t> pcm_buffer_;
    std::thread worker_;
    std::atomic<bool> stop_;
    std::atomic<bool> paused_;
    std::atomic<bool> playing_{false};
    int sample_rate_;
    int sample_ch_;
    std::string last_error_;
    EventCallback *callback_ = nullptr;
};